|
This Article Is Taken From The Game Programming MegaSite, A Definitive Resource For Game Developers! |
Back in the early days, games did not use a timer to control game play As a result, those games are too fast for our PC's of the late 90's. These games' reference of time is not in sync with the reference of time of our PCs today. You have probably noticed that games like Duke Nukem (the 2D one) came with several versions for different processor speeds (not really processor types). Do this for different processor types, not processor speeds. Why should you bother writing two versions of the same game for a low-end Pentium 90 and a high-end Pentium 200? For the processor is the same, the instructions are the same; only the speed is different. On the other hand, your game might benefit if you write different versions of it for different generations of processors, such as the 486, Pentium, MMX, and Pentium II, all of which are still common (these are the processors of the 90's, for those of you reading this in the years beyond 2000). I have seen demos that had a frame cap; they had a timer that lagged them to 18.2 fps on all processors. The slow processors would just try to make the cut. I've seen worse in code where people use FOR loop delays (which run normally on the authors PC, but run too fast or too slow for everyone else).
If you play a game that is really choppy or really smooth, it is likely to use a timer. The processor speed for which the game is balanced between smooth and choppy is usually the recommended processor speed for the game. These games either skip frames if they're lagging or redraw frames if they're moving too quickly. Games that do this might be able to run 1000 fps but will run as if they can only achieve 30 fps but really smooth, while on a slower PC it will look as it is 30 fps but is really choppy and runs at 10 fps. These games can be played on PCs of any speed, and will run at the same units per second as on the next.
Well, you must find the most accurate timer on you PC. You want a timer that updates no faster than every millisecond. x86 PCs have a nice hardware clock that runs at 1193180hz (1.13198 MHz), microsecond resolution. Find it and use it. Once you have a timer, you need to make it a floating-point precision timer (let's call it "ftime()"); use doubles for this, since most timers use 64-bit integers. For making a floating-point precision timer, just get the timer's value and divide by its rate:
double ftime(void) { return super_fast_clock()/the_rate_of_the_clock; }
We would move all objects based on how each frame performs, the frame time. To get the frame time you begin by getting the time that the frame starts. You then get the time at which the frame ends, and subtract, as follows:
float framestart,frameend,frametime,fps; framestart=ftime(); // get the first time // game loop do { do { // get the time till its not equal to start frame time, it should, // never loop at the rate of this timer, but if it does then // it will cap to the frame rate to the rate of this timer which // is 1193180 Hz frameend=ftime(); // get end of frame time } while(frameend==framestart); frametime=frameend-framestart; // find difference to get the frametime framestart=frameend; // make the first time be the next time // the inverse of frame time is the frame rate fps=1.0/frametime; // pretty cool huh // other game stuff } while(game_is_running);
If you added all of the frame times together for 1 second, the resultant value would equal 1. Declare your movement variables for a game in single-precision floating-point. You need this precision because the frame time could be as small as 1/1193180. Declare your units per second variables in floats also to whatever rate as well. To move your game objects at that rate, you multiply the objects' rates by their units per second motion constant. Here is what it looks like:
players.location_x+=players.x_units_per_second*frametime;
Note: No matter how fast your processor is, everything will move at a given number of units per second, because for each second, the sum of frame-times will be one. Total time is equal to all the frame times added together, they work on a ratio of 1:1.
For flipping sprites you would do the same. You would have to declare a float variable that keeps track of the current frame. Also, you would limit the frames drawn per second.
sprite.fcurrentframe+=sprite.framespersecond*frametime; if(sprite.fcurrentframe>sprite.totalframes) { int isoverby=sprite.fcurrentframe/sprite.totalframes; sprite.fcurrentframe-=mesprite.totalframes*isoverby; } sprite.icurrentframe=(int)sprite.fcurrentframe; sprite_draw(&sprite);
This skips frames if you have a slow PC, and on a fast PC it will run every frame but no more than sprite.framespersecond.
If you wanted to make a delay it would be as easy. I would not recommend adding a delay, but I guess it's good for...nothing. Well just kidding it would have its uses for like reading a port for x seconds. Here is what it would look like:
float start=ftime(); while(ftime()-start<num_seconds) { // you can put code here }
Remember, everything that moves should be using the frametime. Also everything that moves should have its own units per second variable. Now that you have this knowledge, you can create a game that uses real time. Your game will look and feel professional.